﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Krile.Kernel.Control;
using System.IO;
using System.Drawing.Imaging;
using Krile.Kernel;
using Krile.Kernel.WindowsEx;

namespace Wassrile.Controls
{
    public partial class WInput : UserControl, IInputMethod
    {
        public Krile.Kernel.Bridges.IInputControlManager ParentICM { get; set; }
        
        public WInput()
        {
            InitializeComponent();
            inputText.Font = Bridge.Config.DisplayConfig.RenderingFont;
        }

        public MethodInvoker CancelCallback { get; set; }

        public void Cancelled()
        {
            if (palletdlg != null)
            {
                palletdlg.Close();
                palletdlg.Dispose();
                palletdlg = null;
            }
        }

        public void Clear()
        {
            inputText.Clear();
            if (palletdlg != null)
            {
                palletdlg.Close();
            }
            linkedPicturePath.Text = "なし";
            linkedPicturePath.Enabled = false;
            linkPicture = null;
            postToCh = null;
        }

        public object ExtraData
        {
            get
            {
                if (String.IsNullOrEmpty(linkPicture) && String.IsNullOrEmpty(postToCh))
                    return null;
                else
                    return new WExtraData(linkPicture, postToCh);
            }
            set
            {
                if (value == null || !(value is WExtraData) )
                    return;
            }
        }

        public void FocusToInput()
        {
            inputText.Focus();
        }

        public string IdentifyString
        {
            get { return Define.InputMethodId; }
        }

        public string InputText
        {
            get
            {
                return inputText.Text;
            }
            set
            {
                inputText.Text = value;
            }
        }

        public MethodInvoker PostCallback { get; set; }

        private void PostButton_Click(object sender, EventArgs e)
        {
            PostCallback.Invoke();
        }

        private void ColoringBar_Click(object sender, EventArgs e)
        {
            ColorBar.Visible = ColoringBar.Checked;
        }

        Dialogs.PictPalletDlg palletdlg = null;
        private void PictoPallet_Click(object sender, EventArgs e)
        {
            if (palletdlg != null)
            {
                palletdlg.Close();
                palletdlg = null;
                PictoPallet.Checked = false;
                return;
            }
            palletdlg = new Wassrile.Dialogs.PictPalletDlg();
            if (Core.Config.Behavior.PictPallet.saveSize)
                palletdlg.Size = Core.Config.State.PalletSize;
            palletdlg.Location =
                Core.Config.Behavior.PictPallet.saveLocation ?
                Core.Config.State.PalletLoc :
                MainStrip.PointToScreen(new Point());
            palletdlg.Top -= palletdlg.Size.Height;
            palletdlg.PalletClicked += new Wassrile.Dialogs.Pictogram.PictogramSet.ClickPallet(palletdlg_PalletClicked);
            palletdlg.Disposed += new EventHandler(palletdlg_Disposed);
            ParentICM.AppendChild(palletdlg);
            palletdlg.Show();
        }

        void palletdlg_Disposed(object sender, EventArgs e)
        {
            palletdlg = null;
            PictoPallet.Checked = false;
        }

        void palletdlg_PalletClicked(object sender, Wassrile.Dialogs.Pictogram.PictogramSet.StringEventArgs e)
        {
            inputText.SelectedText = "{emoji:" + e.code + "}";
        }

        private void SetColor_Click(object sender, EventArgs e)
        {
            if (inputText.SelectedText == String.Empty)
            {
                MessageBoxEx.Show("着色エラー",
                    "色付けしたい文字を選択してからクリックしてください。",
                    "Wassr文字着色",
                    MessageBoxEx.MessageBoxExButtons.Close, MessageBoxEx.MessageBoxExIcon.Warning);
                return;
            }
            inputText.SelectedText = "{color:" + ((ToolStripButton)sender).Name + ":" + inputText.SelectedText + "}";
        }

        public class WExtraData
        {
            public string LinkPicturePath = null;
            public string ChannelId = null;
            public WExtraData() { }
            public WExtraData(string lpict, string ch)
            {
                LinkPicturePath = lpict;
                ChannelId = ch;
            }
        }

        private void MainText_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.A && e.Control)
            {
                e.Handled = true;
                e.SuppressKeyPress = true;
                inputText.SelectAll();
            }
            else if (e.KeyCode == Keys.Enter && e.Control)
            {
                e.Handled = true;
                e.SuppressKeyPress = true;
                PostCallback();
                return;
            }
            else
                ProcessIntelliNantoka(e);
        }

        string linkPicture = null;
        private void LinkPicture_ButtonClick(object sender, EventArgs e)
        {
            using (var ofd = new OpenFileDialog())
            {
                ofd.Filter = "アップロード可能な画像ファイル|*.jpg;*.jpeg;*.png|すべてのファイル|*.*";
                ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    linkedPicturePath.Text = "添付(クリックで解除):" + ofd.FileName;
                    linkedPicturePath.Enabled = true;
                    linkPicture = ofd.FileName;
                }
            }
        }

        private void linkedPicturePath_Click(object sender, EventArgs e)
        {
            if (linkPicture != null)
            {
                if (MessageBoxEx.Show(
                    "画像の添付設定がされています。",
                    "添付を解除しますか？",
                    "画像の添付",
                    MessageBoxEx.MessageBoxExButtons.YesNo, MessageBoxEx.MessageBoxExIcon.Question) == MessageBoxEx.DialogResultEx.Yes)
                {
                    linkPicture = null;
                    linkedPicturePath.Text = "なし";
                    linkedPicturePath.Enabled = false;
                }
            }
        }

        private void CaptureDesktop_Click(object sender, EventArgs e)
        {
            using(var cf = new CaptureFrame())
            {
                if (cf.ShowDialog() == DialogResult.OK)
                {
                    Application.DoEvents();
                    Rectangle target = cf.Target;
                    using (Bitmap bmp = new Bitmap(target.Width, target.Height, PixelFormat.Format32bppArgb))
                    {
                        using (Graphics g = Graphics.FromImage(bmp))
                        {
                            g.CopyFromScreen(target.X, target.Y, 0, 0,
                              target.Size, CopyPixelOperation.SourceCopy);
                        }
                        using (var sfd = new SaveFileDialog())
                        {
                            try
                            {
                                sfd.Filter = "PNG画像|*.png|JPEG画像|*.jpg|すべてのファイル|*.*";
                                if (sfd.ShowDialog() == DialogResult.OK)
                                {
                                    bmp.Save(sfd.FileName);
                                }
                                linkedPicturePath.Text = "添付(クリックで解除):" + sfd.FileName;
                                linkedPicturePath.Enabled = true;
                                linkPicture = sfd.FileName;
                            }
                            catch (Exception ex)
                            {
                                MessageBoxEx.Show(
                                    "画像リンクエラー",
                                    ex.Message, "画像リンクエラー",
                                    MessageBoxEx.MessageBoxExButtons.Close, MessageBoxEx.MessageBoxExIcon.Error);
                            }
                        }
                    }
                }
            }
        }

        string postToCh = null;
        private void ChSelector_Click(object sender, EventArgs e)
        {
            using (var chs = new Dialogs.ChSelector())
            {
                if (chs.ShowDialog() == DialogResult.OK)
                {
                    if (!String.IsNullOrEmpty(chs.SelectedChannel))
                        inputText.Text = "#" + chs.SelectedChannel + " " + inputText.Text;
                    inputText.SelectionStart = inputText.Text.Length;
                    inputText.Focus();
                }
            }
        }

        public void SetChannel(string id)
        {
            if (!String.IsNullOrEmpty(id))
                inputText.Text = "#" + id + " " + inputText.Text;
            inputText.SelectionStart = inputText.Text.Length;
            inputText.Focus();
        }

        const int MaxInput = 255;
        private void MainText_TextChanged(object sender, EventArgs e)
        {
            remainLabel.Text = "[" + inputText.Text.Length.ToString() + "/" + MaxInput.ToString() + "]";
            if (inputText.Text.Length <= MaxInput)
                remainLabel.ForeColor = SystemColors.GrayText;
            else
                remainLabel.ForeColor = Color.Red;
            ProcessIntelliNantokaInput();
        }

        public bool OnReplyRequired(ulong uid)
        {
            if (Bridge.StatusManager.IdExists(uid) &&
                Bridge.StatusManager.GetStatus(uid) is Operation.DataClasses.WStatus)
            {
                if (Core.Config.Post.replyToFav && ((Operation.DataClasses.WStatus)Bridge.StatusManager.GetStatus(uid)).Favored == false)
                {
                    Core.Plugin.WOperation.Status.SetFavorite(uid, true);
                }
                if (((Operation.DataClasses.WStatus)Bridge.StatusManager.GetStatus(uid)).channelId != null)
                {
                    SetChannel(((Operation.DataClasses.WStatus)Bridge.StatusManager.GetStatus(uid)).channelId);
                }
            }
            return true;
        }


        //インテリなんとか制御
        bool IsUsingIntelli = false;
        Dialogs.IntelliNantoka nantokaDlg = null;
        int oldLength = 0;
        int startpoint = -1;
        bool pictgramFormat = false;
        bool prevSSWithSuccessed = true;
        private void ProcessIntelliNantoka(KeyEventArgs e)
        {
            if (!Core.Config.Behavior.UseSuggest) return;
            if (IsUsingIntelli && nantokaDlg != null)
            {
                e.Handled = true;
                e.SuppressKeyPress = true;
                switch (e.KeyCode)
                {
                    case Keys.Tab:
                    case Keys.Escape:
                        IsUsingIntelli = false;
                        if (nantokaDlg != null)
                            nantokaDlg.Visible = false;
                        break;
                    case Keys.Space:
                    case Keys.Enter:
                        nantokaDlg_OnDecided(null, null);
                        IsUsingIntelli = false;
                        if (nantokaDlg != null)
                            nantokaDlg.Visible = false;
                        break;
                    case Keys.Up:
                        nantokaDlg.MoveAboveItem();
                        break;
                    case Keys.Down:
                        nantokaDlg.MoveBelowItem();
                        break;
                    default:
                        e.Handled = false;
                        e.SuppressKeyPress = false;
                        break;
                }
            }
        }

        private void ProcessIntelliNantokaInput()
        {
            if (!Core.Config.Behavior.UseSuggest) return;
            if (IsUsingIntelli)
            {
                if (inputText.Text.Length < startpoint ||
                    (inputText.Text[startpoint - 1] != '#' && inputText.Text[startpoint - 1] != '@' && inputText.Text[startpoint - 1] != '{'))
                {
                    //abort
                    IsUsingIntelli = false;
                    nantokaDlg.Visible = false;
                }
                else
                {
                    string varval = inputText.Text.Substring(startpoint).Split(' ', '\n', '\t', '\r')[0];
                    if (varval.Length <= 0)
                        prevSSWithSuccessed = nantokaDlg.SelectStartsWith(null);
                    else
                        prevSSWithSuccessed = nantokaDlg.SelectStartsWith(varval);
                }
            }
            else
            {
                //Check IntelliNantoka Hitting
                //1文字だけ入力された
                if (inputText.Text.Length == oldLength + 1)
                {
                    if (inputText.SelectionStart > 0 && inputText.SelectionStart <= inputText.Text.Length)
                    {
                        if (inputText.Text[inputText.SelectionStart - 1] == '#' && inputText.SelectionStart == 1)
                        {
                            //文頭のみ
                            startpoint = inputText.SelectionStart;
                            List<string> dat = new List<string>();
                            foreach(var i in Operation.Web.DataMan.GetChannels())
                            {
                                dat.Add(i.Key + "%[" + i.Value + "]");
                            }
                            pictgramFormat = false;
                            ShowNantoka(dat.ToArray(), Properties.Resources.channel, startpoint - 1);
                        }
                        else if (inputText.Text[inputText.SelectionStart - 1] == '@')
                        {
                            startpoint = inputText.SelectionStart;
                            var dat = Operation.Web.DataMan.GetUsers().ToArray<string>();
                            pictgramFormat = false;
                            ShowNantoka(dat, Properties.Resources.user, startpoint - 1);
                        }
                        else if (inputText.Text[inputText.SelectionStart - 1] == '{')
                        {
                            //絵文字
                            if (Core.Config.Behavior.PictPallet.customPalletItems != null &&
                                Core.Config.Behavior.PictPallet.customPalletItems.Length > 0)
                            {
                                startpoint = inputText.SelectionStart;
                                pictgramFormat = true;
                                ShowNantoka(Core.Config.Behavior.PictPallet.customPalletItems,
                                    new Wassrile.Dialogs.IntelliNantoka.DisplayCallback(
                                        delegate(string k, ref string s){
                                            return Core.PictogramResolver.GetPictogram(k);
                                        }),startpoint - 1);
                            }
                        }
                    }
                }
            }
            oldLength = inputText.Text.Length;
        }

        private void ShowNantoka(string[] data, Image img, int startidx)
        {
            if (!Core.Config.Behavior.UseSuggest) return;
            if (data == null || data.Length == 0) return;
            prevSSWithSuccessed = true;
            IsUsingIntelli = true;
            if (nantokaDlg != null)
                nantokaDlg.Dispose();
            nantokaDlg = new Wassrile.Dialogs.IntelliNantoka(this, data, img);
            nantokaDlg.Location = inputText.PointToScreen(inputText.GetPositionFromCharIndex(startidx));
            Rectangle rec = Screen.PrimaryScreen.Bounds;
            double point = inputText.Font.Size;
            Graphics g = this.CreateGraphics();
            point *= g.DpiY / 72.0;
            g.Dispose();
            nantokaDlg.Top += (int)point + 4; // 4:margin
            nantokaDlg.OnDecided += new EventHandler(nantokaDlg_OnDecided);
            nantokaDlg.OnWindowHided += new EventHandler(nantokaDlg_OnWindowHided);
            ParentICM.AppendChild(nantokaDlg);
            nantokaDlg.Show();
        }
        private void ShowNantoka(string[] data, Dialogs.IntelliNantoka.DisplayCallback callback, int startidx)
        {
            if (!Core.Config.Behavior.UseSuggest) return;
            if (data == null || data.Length == 0) return;
            prevSSWithSuccessed = true;
            IsUsingIntelli = true;
            if (nantokaDlg != null)
                nantokaDlg.Dispose();
            nantokaDlg = new Wassrile.Dialogs.IntelliNantoka(this, data, callback);
            nantokaDlg.Location = inputText.PointToScreen(inputText.GetPositionFromCharIndex(startidx));
            Rectangle rec = Screen.PrimaryScreen.Bounds;
            double point = inputText.Font.Size;
            Graphics g = this.CreateGraphics();
            point *= g.DpiY / 72.0;
            g.Dispose();
            nantokaDlg.Top += (int)point + 4; // 4:margin
            nantokaDlg.OnDecided += new EventHandler(nantokaDlg_OnDecided);
            nantokaDlg.OnWindowHided += new EventHandler(nantokaDlg_OnWindowHided);
            ParentICM.AppendChild(nantokaDlg);
            nantokaDlg.Show();
        }

        void nantokaDlg_OnWindowHided(object sender, EventArgs e)
        {
            nantokaDlg.Close();
            nantokaDlg = null;
        }

        void nantokaDlg_OnDecided(object sender, EventArgs e)
        {
            if (IsUsingIntelli && prevSSWithSuccessed)
            {
                var str = nantokaDlg.DecidedItem;
                if (pictgramFormat)
                {
                    str = "emoji:" + str + "}";
                }
                int selectLen = inputText.SelectionStart;
                inputText.SelectionStart = startpoint;
                selectLen = selectLen - inputText.SelectionStart;
                if (selectLen < 0) selectLen = 0;
                inputText.SelectionLength = selectLen;
                inputText.SelectedText = str + " ";
                IsUsingIntelli = false;
                if (nantokaDlg != null)
                    nantokaDlg.Visible = false;
            }
        }

        private void WInput_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Up:
                case Keys.Down:
                case Keys.Escape:
                    if ((e.KeyData & Keys.Modifiers) == Keys.None && IsUsingIntelli)
                        e.IsInputKey = true;
                    break;
            }
        }
    }
}
